﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;
using MyUi_WPF_Controls.DataGridCtr.Base;

namespace MyUi_WPF_Controls.DataGridCtr
{
    public class LayDataGrid : DataGrid
    {
        private const string PART_Right = "PART_Right";
        private const string PART_ScrollViewer = "DG_ScrollViewer";

        private MyDataGridScrollView _rightDataGrid;
        private ScrollViewer _rightScrollViewer;
        private ScrollViewer _scrollViewer;
        /// <summary>
        /// 记录行刷新状态 用于行刷新
        /// </summary>
         bool isRefresh = false;

        [Bindable(true)]
        public Thickness DateGridBorderThickness
        {
            get { return (Thickness)GetValue(DateGridBorderThicknessProperty); }
            set { SetValue(DateGridBorderThicknessProperty, value); }
        }

        // Using a DependencyProperty as the backing store for EditingComboBoxColumnStyle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DateGridBorderThicknessProperty =
            DependencyProperty.Register("DateGridBorderThickness", typeof(Thickness), typeof(LayDataGrid), new PropertyMetadata(new Thickness(1, 0, 1, 0)));


        [Bindable(true)]
        public Style ElementCheckBoxColumnStyle
        {
            get { return (Style)GetValue(ElementCheckBoxColumnStyleProperty); }
            set { SetValue(ElementCheckBoxColumnStyleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for EditingComboBoxColumnStyle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElementCheckBoxColumnStyleProperty =
            DependencyProperty.Register("ElementCheckBoxColumnStyle", typeof(Style), typeof(LayDataGrid), new PropertyMetadata(default(Style), OnCheckBoxColumnStyleChanged));

        [Bindable(true)]
        public Style EditingCheckBoxColumnStyle
        {
            get { return (Style)GetValue(EditingCheckBoxColumnStyleProperty); }
            set { SetValue(EditingCheckBoxColumnStyleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for EditingCheckBoxColumnStyle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EditingCheckBoxColumnStyleProperty =
            DependencyProperty.Register("EditingCheckBoxColumnStyle", typeof(Style), typeof(LayDataGrid), new PropertyMetadata(default(Style), OnCheckBoxColumnStyleChanged));

        private static void OnCheckBoxColumnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is LayDataGrid layDataGrid)
            {
                if (e.OldValue == null && e.NewValue != null)
                {
                    layDataGrid.UpdateCheckBoxColumnStyles(layDataGrid);
                }
            }
        }

        /// <summary>
        /// 更新复选框样式
        /// </summary>
        /// <param name="layDataGrid"></param>
        protected void UpdateCheckBoxColumnStyles(LayDataGrid layDataGrid)
        {
            var checkBoxColumnStyle = ElementCheckBoxColumnStyle;
            var editingCheckBoxColumnStyle = EditingCheckBoxColumnStyle;

            if (checkBoxColumnStyle != null)
            {
                foreach (var column in layDataGrid.Columns.OfType<DataGridCheckBoxColumn>())
                {
                    var elementStyle = new Style
                    {
                        BasedOn = column.ElementStyle,
                        TargetType = checkBoxColumnStyle.TargetType
                    };

                    foreach (var setter in checkBoxColumnStyle.Setters.OfType<Setter>())
                    {
                        elementStyle.Setters.Add(setter);
                    }

                    column.ElementStyle = elementStyle;
                }
            }

            if (editingCheckBoxColumnStyle != null)
            {
                foreach (var column in layDataGrid.Columns.OfType<DataGridCheckBoxColumn>())
                {
                    var editingElementStyle = new Style
                    {
                        BasedOn = column.EditingElementStyle,
                        TargetType = editingCheckBoxColumnStyle.TargetType
                    };

                    foreach (var setter in editingCheckBoxColumnStyle.Setters.OfType<Setter>())
                    {
                        editingElementStyle.Setters.Add(setter);
                    }

                    column.EditingElementStyle = editingElementStyle;
                }
            }
        }

        [Bindable(true)]
        public Style ElementComboBoxColumnStyle
        {
            get { return (Style)GetValue(ElementComboBoxColumnStyleProperty); }
            set { SetValue(ElementComboBoxColumnStyleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ElementComboBoxColumnStyle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElementComboBoxColumnStyleProperty =
            DependencyProperty.Register("ElementComboBoxColumnStyle", typeof(Style), typeof(LayDataGrid), new PropertyMetadata(default(Style), OnComboBoxColumnStyleChanged));

        [Bindable(true)]
        public Style EditingComboBoxColumnStyle
        {
            get { return (Style)GetValue(EditingComboBoxColumnStyleProperty); }
            set { SetValue(EditingComboBoxColumnStyleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for EditingComboBoxColumnStyle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EditingComboBoxColumnStyleProperty =
            DependencyProperty.Register("EditingComboBoxColumnStyle", typeof(Style), typeof(LayDataGrid), new PropertyMetadata(default(Style), OnComboBoxColumnStyleChanged));

        private static void OnComboBoxColumnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is LayDataGrid layDataGrid)
            {
                if (e.OldValue == null && e.NewValue != null)
                {
                    //layDataGrid.UpdateComboBoxColumnStyles(layDataGrid);
                }
            }
        }
        /// <summary>
        /// 更新下拉框样式
        /// </summary>
        /// <param name="layDataGrid"></param>
        protected void UpdateComboBoxColumnStyles(LayDataGrid layDataGrid)
        {
            var comboBoxColumnStyle = ElementComboBoxColumnStyle;
            var editingComboBoxColumnStyle = EditingComboBoxColumnStyle;

            if (comboBoxColumnStyle != null)
            {
                foreach (var column in layDataGrid.Columns.OfType<DataGridComboBoxColumn>())
                {
                    var elementStyle = new Style
                    {
                        BasedOn = column.ElementStyle,
                        TargetType = comboBoxColumnStyle.TargetType
                    };

                    foreach (var setter in comboBoxColumnStyle.Setters.OfType<Setter>())
                    {
                        elementStyle.Setters.Add(setter);
                    }

                    column.ElementStyle = elementStyle;
                }
            }

            if (editingComboBoxColumnStyle != null)
            {
                foreach (var column in layDataGrid.Columns.OfType<DataGridComboBoxColumn>())
                {
                    var editingElementStyle = new Style
                    {
                        BasedOn = column.EditingElementStyle,
                        TargetType = editingComboBoxColumnStyle.TargetType
                    };

                    foreach (var setter in editingComboBoxColumnStyle.Setters.OfType<Setter>())
                    {
                        editingElementStyle.Setters.Add(setter);
                    }

                    column.EditingElementStyle = editingElementStyle;
                }
            }
        }
        [Bindable(true)]
        public Style ElementTextColumnStyle
        {
            get { return (Style)GetValue(ElementTextColumnStyleProperty); }
            set { SetValue(ElementTextColumnStyleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ElementTextStyle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ElementTextColumnStyleProperty =
            DependencyProperty.Register("ElementTextColumnStyle", typeof(Style), typeof(LayDataGrid), new PropertyMetadata(default(Style), OnTextColumnStyleChanged));

        [Bindable(true)]
        public Style EditingTextColumnStyle
        {
            get { return (Style)GetValue(EditingTextColumnStyleProperty); }
            set { SetValue(EditingTextColumnStyleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for EditingTextColumnStyle.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty EditingTextColumnStyleProperty =
            DependencyProperty.Register("EditingTextColumnStyle", typeof(Style), typeof(LayDataGrid), new PropertyMetadata(default(Style), OnTextColumnStyleChanged));

        private static void OnTextColumnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is LayDataGrid layDataGrid)
            {
                if (e.OldValue == null && e.NewValue != null)
                {
                    layDataGrid.UpdateTextColumnStyles(layDataGrid);
                }
            }
        }
        /// <summary>
        /// 更新文本样式
        /// </summary>
        /// <param name="grid"></param>
        protected void UpdateTextColumnStyles(LayDataGrid grid)
        {
            var textColumnStyle = ElementTextColumnStyle;
            var editingTextColumnStyle = EditingTextColumnStyle;
            if (textColumnStyle != null)
            {
                foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
                {
                    var elementStyle = new Style
                    {
                        BasedOn = column.ElementStyle,
                        TargetType = textColumnStyle.TargetType
                    };

                    foreach (var setter in textColumnStyle.Setters.OfType<Setter>())
                    {
                        elementStyle.Setters.Add(setter);
                    }

                    column.ElementStyle = elementStyle;
                }
            }
            if (editingTextColumnStyle != null)
            {
                foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
                {
                    var editingElementStyle = new Style
                    {
                        BasedOn = column.EditingElementStyle,
                        TargetType = editingTextColumnStyle.TargetType,
                    };

                    foreach (var setter in editingTextColumnStyle.Setters.OfType<Setter>())
                    {
                        editingElementStyle.Setters.Add(setter);
                    }

                    column.EditingElementStyle = editingElementStyle;
                }
            }
        }
        
        [Bindable(true)]
        public bool IsShowRowsFocusVisual
        {
            get { return (bool)GetValue(IsShowRowsFocusVisualProperty); }
            set { SetValue(IsShowRowsFocusVisualProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsShowRowsFocusVisual.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsShowRowsFocusVisualProperty =
            DependencyProperty.Register("IsShowRowsFocusVisual", typeof(bool), typeof(LayDataGrid), new PropertyMetadata(false));


        /// <summary>
        /// 无数据提示信息
        /// </summary>
        [Bindable(true)]
        public string NoDataTips
        {
            get { return (string)GetValue(NoDataTipsProperty); }
            set { SetValue(NoDataTipsProperty, value); }
        }

        // Using a DependencyProperty as the backing store for NoDataTips.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty NoDataTipsProperty =
            DependencyProperty.Register("NoDataTips", typeof(string), typeof(LayDataGrid), new PropertyMetadata("暂无数据"));
        /// <summary>
        /// 动画开关
        /// </summary>
        [Bindable(true)]
        public bool IsActive
        {
            get { return (bool)GetValue(IsActiveProperty); }
            set { SetValue(IsActiveProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsActive.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsActiveProperty =
            DependencyProperty.Register("IsActive", typeof(bool), typeof(LayDataGrid), new PropertyMetadata(false));


        #region Right
        private static readonly DependencyPropertyKey RightFrozenColumnsViewportLengthPropertyKey = DependencyProperty.RegisterReadOnly(
    "RightFrozenColumnsViewportLength", typeof(double), typeof(LayDataGrid), new PropertyMetadata(
        0d));
        public static readonly DependencyProperty RightFrozenColumnsViewportLengthProperty = RightFrozenColumnsViewportLengthPropertyKey.DependencyProperty;
        public double RightFrozenColumnsViewportLength
        {
            get { return (double)GetValue(RightFrozenColumnsViewportLengthProperty); }
            internal set { SetValue(RightFrozenColumnsViewportLengthPropertyKey, value); }
        }


        public int RightFrozenCount
        {
            get
            {
                return (int)GetValue(RightFrozenCountProperty);
            }
            set
            {
                SetValue(RightFrozenCountProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for RightFrozenCount.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty RightFrozenCountProperty =
            DependencyProperty.Register(nameof(RightFrozenCount), typeof(int), typeof(LayDataGrid), new PropertyMetadata(0, OnRightFrozenCountChanged));

        private static void OnRightFrozenCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is LayDataGrid LayDataGrid)
            {
                LayDataGrid.OnRightFrozenCountChanged();
            }
        }

        private void OnRightFrozenCountChanged()
        {
            if (RightFrozenCount > 0)
            {
                DateGridBorderThickness = new Thickness(1, 0, 0, 0);
            }
            else
            {
                DateGridBorderThickness = new Thickness(1, 0, 1, 0);
            }
            if (_rightDataGrid != null)
            {
                _rightDataGrid.RowHeight = this.RowHeight;
                if (RightFrozenCount > 0)
                {
                    for (int i = 0; i <_rightDataGrid.Columns.Count; i++)
                    {
                        var column = _rightDataGrid.Columns[i];
                        _rightDataGrid.Columns.Remove(column);
                      
                        this.Columns.Add(column);
                    }
                    for (int i = 0; i < RightFrozenCount; i++)
                    {
                        var last = Columns[Columns.Count - 1];
                        this.Columns.Remove(last);

                        _rightDataGrid.Columns.Insert(0, last);
                    }
                    _rightDataGrid.SetCurrentValue(VisibilityProperty, Visibility.Visible);
                }
                else
                {
                    _rightDataGrid.SetCurrentValue(VisibilityProperty, Visibility.Collapsed);
                }
            }
        }

        #endregion

        public LayDataGrid() 
        {
            this.Loaded += LayDataGrid_Loaded;           
        }

        private void LayDataGrid_Loaded(object sender, RoutedEventArgs e)
        {
            OnRightFrozenCountChanged();
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            UpdateTextColumnStyles(this);
            UpdateComboBoxColumnStyles(this);
            UpdateCheckBoxColumnStyles(this);

            if (_scrollViewer != null)
            {
                _scrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged;
            }

            if (_rightScrollViewer != null)
            {
                _rightScrollViewer.ScrollChanged -= _rightScrollViewer_ScrollChanged;
            }
            if (_rightDataGrid != null)
            {
                _rightDataGrid.ScrollViewerChanged -= ScrollViewerChanged;
                _rightDataGrid.SelectionChanged -= _rightDataGrid_SelectionChanged;
            }

            _scrollViewer = GetTemplateChild(PART_ScrollViewer) as ScrollViewer;
            if (_scrollViewer != null)
            {
                _scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;
            }

            _rightDataGrid = GetTemplateChild(PART_Right) as MyDataGridScrollView;
            if (_rightDataGrid != null)
            {
                _rightDataGrid.ScrollViewerChanged += ScrollViewerChanged;
                _rightDataGrid.SelectionChanged += _rightDataGrid_SelectionChanged;
            }
            this.SelectionChanged += DataGridRightFrozen_SelectionChanged;
        }
        private void DataGridRightFrozen_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (_rightDataGrid!=null) 
            {
                _rightDataGrid.SetCurrentValue(SelectedItemProperty, SelectedItem);
            }
           
        }
        private void ScrollViewerChanged(ScrollViewer viewer)
        {
            _rightScrollViewer = viewer;
            _rightScrollViewer.ScrollChanged += _rightScrollViewer_ScrollChanged;
        }

        private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (_rightScrollViewer != null)
            {
                _rightScrollViewer?.ScrollToVerticalOffset(_scrollViewer.VerticalOffset);
            }
        }

        private void _rightScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (_scrollViewer != null)
            {
                _scrollViewer?.ScrollToVerticalOffset(_rightScrollViewer.VerticalOffset);
            }
        }

        private void _rightDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            this.SetCurrentValue(SelectedItemProperty, _rightDataGrid.SelectedItem);
        }
        /// <summary>
        /// 监听行变化
        /// </summary>
        /// <param name="e"></param>
        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);
            if (e.Action != NotifyCollectionChangedAction.Add)
            {
                //防止当前视图出现递归刷新
                if (!isRefresh)
                {
                    isRefresh = true;
                    /////////重新渲染视图/////////
                    this.Items.Refresh();
                    isRefresh = false;
                }
            }
        }
        protected override void OnLoadingRow(DataGridRowEventArgs e)
        {
            base.OnLoadingRow(e);
            LayDataGridHelper.SetLineNumber(e.Row, e.Row.GetIndex() + 1);
        }
    }

}
